class MagnifyingGlass {
  // 需要放大的图片
  imgEl;
  // 放大预览视图
  magnifyingGlassView;
  // 区域小图
  smallCanvas;
  // 保存原图的像素值
  originalPiexls = [];
  // 截流定时器
  interceptionTimer = null;

  constructor(el) {
    if (el.tagName == "IMG") {
      this.imgEl = el;
      this.listenerImgLoadSucceeded();
    }
  }

  // 监听图片加载完成
  async listenerImgLoadSucceeded() {
    if (!this.imgEl.complete) {
      await new Promise((resolve) => {
        this.imgEl.onload = resolve;
      });
    }

    // 添加鼠标事件
    this.addMouseEvent();
    // 创建一个放大预览视图
    this.createMagnifyingGlassView();
  }

  // 创建一个放大预览视图
  createMagnifyingGlassView() {
    if (this.magnifyingGlassView) {
      this.magnifyingGlassView.remove();
    }
    this.magnifyingGlassView = document.createElement("canvas");
    this.magnifyingGlassView.style.cssText =
      "position: fixed;background:aliceblue;left:0;top:0;pointer-events:none;display:none";
    this.magnifyingGlassView.setAttribute("width", `${200}px`);
    this.magnifyingGlassView.setAttribute("height", `${200}px`);
    let body = document.getElementsByTagName("body")[0];
    body.appendChild(this.magnifyingGlassView);
  }

  // 添加鼠标事件
  addMouseEvent() {
    // 添加鼠标滑过事件
    this.addMouseMoveToImageEl();
    // 鼠标滑出事件
    this.addMouseLeaveToImageEl();
  }

  // 添加鼠标滑过事件
  addMouseMoveToImageEl() {
    this.imgEl.onmousemove = (event) => {
      let x = event.clientX + this.getElementPosition(this.imgEl).left + 20;
      let y = event.clientY + this.getElementPosition(this.imgEl).top + 20;
      let position = { x, y };
      console.log(x, y);
      // 截流
      this.interceptionFunc(() => {
        // 修改放大视图位置
        this.changeMagnifyingGlassViewPosition(position);
        // 获取需要放大的像素
        this.getNeedMasgnifyingGlassPiexl({
          clientX: event.clientX - this.getElementPosition(this.imgEl).left,
          clientY: event.clientY - this.getElementPosition(this.imgEl).top,
        });
      });
    };
  }

  //截流
  interceptionFunc(cb) {
    if (this.interceptionTimer) {
      return;
    }
    this.interceptionTimer = setTimeout(() => {
      cb();
      this.interceptionTimer = null;
    }, 20);
  }

  // 鼠标滑出事件
  addMouseLeaveToImageEl() {
    this.imgEl.onmouseleave = () => {
      // 移除放大框
      setTimeout(() => {
        console.log(111);
        this.magnifyingGlassView.style.display = "none";
        console.log(this.magnifyingGlassView.style.display);
      }, 20);
    };
  }

  // 修改放大视图位置
  changeMagnifyingGlassViewPosition(position) {
    // this.magnifyingGlassView.style.left = position.x + "px";
    // this.magnifyingGlassView.style.top = position.y + "px";
    this.magnifyingGlassView.style.left = "550px";
    this.magnifyingGlassView.style.top = "300px";
    this.magnifyingGlassView.style.display = "block";
  }

  // 获取元素在屏幕的位置
  getElementPosition(element) {
    var top = element.offsetTop;
    var left = element.offsetLeft;
    var currentParent = element.offsetParent;
    while (currentParent !== null) {
      top += currentParent.offsetTop;
      left += currentParent.offsetLeft;
      currentParent = currentParent.offsetParent;
    }
    return { top, left };
  }

  // 保存原像素（操作像素点时候用）
  async getOriginalPiexls() {
    if (this.originalPiexls.length == 0) {
      var image = new Image();
      image.src = this.imgEl.src;
      // 等待IMG标签加载完成后保存像素值
      await new Promise((resolve) => {
        image.onload = resolve;
      });
      let width = image.width;
      let height = image.height;
      let canvas = document.createElement("canvas");
      canvas.setAttribute("width", `${width}px`);
      canvas.setAttribute("height", `${height}px`);
      var ctx = canvas.getContext("2d");
      ctx.fillStyle = ctx.createPattern(image, "no-repeat");
      ctx.fillRect(0, 0, width, height);
      try {
        //保存像素
        this.originalPiexls = ctx.getImageData(0, 0, width, height);
      } catch (error) {
        console.log(error);
      }
    }
  }

  // 获取需要放大的像素
  async getNeedMasgnifyingGlassPiexl(event) {
    //获取原始像素
    this.getOriginalPiexls();
    //如果像素为空，不进行操作
    if (this.originalPiexls.length == 0) {
      return;
    }
    //获取待放大IMG的宽度，用来计算像素
    let imageWidth = this.imgEl.offsetWidth;
    //获取当前鼠标点的范围
    let diffusionLength = 100;
    //鼠标触点
    let mouseX = event.clientX;
    let mouseY = event.clientY;
    //规定区域的上下、左右宽度
    let sepX = parseInt(diffusionLength);
    let sepY = parseInt(diffusionLength);
    // 需要开始的点
    let startPoint = {
      x: mouseX - parseInt(sepX / 2.0),
      y: mouseY - parseInt(sepY / 2.0),
    };
    // 需要结束的点
    let endPoint = {
      x: mouseX + parseInt(sepX / 2.0),
      y: mouseY + parseInt(sepY / 2.0),
    };
    // 最终要展示的像素集合(乘以4是单一像素值宽度)
    let finallyOriginalPiexls = new Uint8ClampedArray(sepX * sepY * 4);
    let currentIndex = 0;
    //操作像素
    for (let i = startPoint.y; i < endPoint.y; i++) {
      for (let j = startPoint.x; j < endPoint.x; j++) {
        for (let k = 0; k < 4; k++) {
          let index = (i * imageWidth + j) * 4 + k;
          if (index > 0 && index < this.originalPiexls.data.length) {
            // 超过宽度部分需要进行其他色值填充
            if (j < imageWidth) {
              finallyOriginalPiexls[currentIndex] =
                this.originalPiexls.data[index];
            } else {
              finallyOriginalPiexls[currentIndex] = 199;
            }
          } else {
            finallyOriginalPiexls[currentIndex] = 199;
          }
          currentIndex += 1;
        }
      }
    }

    //先绘制一个100*100单位长的小图
    if (!this.smallCanvas) {
      this.smallCanvas = document.createElement("canvas");
      this.smallCanvas.setAttribute("width", `${diffusionLength}px`);
      this.smallCanvas.setAttribute("height", `${diffusionLength}px`);
    }
    let smallCtx = this.smallCanvas.getContext("2d");
    //初始化ImageData
    let finallyImageData = new ImageData(finallyOriginalPiexls, sepX, sepY);
    // 当前范围内需要放大的像素
    smallCtx.putImageData(
      finallyImageData,
      0,
      0,
      0,
      0,
      diffusionLength,
      diffusionLength
    );
    let url = this.smallCanvas.toDataURL("image/jpeg", 1);

    //将小图绘制到200*200的预览图上
    var image = new Image();
    image.src = url;
    await new Promise((resolve) => {
      image.onload = resolve;
    });
    var magnifyingGlassCtx = this.magnifyingGlassView.getContext("2d");
    magnifyingGlassCtx.drawImage(image, 0, 0, 200, 200);
  }
}
